 /** 
 * This will be the controller handling all operational functions of the parking lot
 * 
 * @author Gil Levinson
 * @author Boris Fradlis
 * @author Yogev Levi
 * @author Hila Porat 
 * 
 * 
 */
package control;

import java.io.Serializable;
import java.sql.Date;
import java.util.concurrent.TimeUnit;

import system.SystemMode;
import system.SystemTypes;
import system.VCP;

//Start of LocalOpertaionController

public class LocalOpertaionController extends AbstractController{

	private SystemTypes sysType;
	private boolean returned = false;
	
	//constructor ****************************************************
	
	/**
	 * default Constructor for our controllers
	 * @param sysType
	 */
	public LocalOpertaionController(SystemTypes sysType) {
		this.sysType = sysType;
		returned = false;
	}
	
	//Controller methods *********************************************
	/**
	 * this method will set the disabling/enabling status of single device (e.g. parking space, row, floor, or the whole lot) for maint. or damage 
	 * @param sysType - expecting instance of the device to disable or to enable and the reason of disable
	 * @return - the proper message.
	 */
	public SystemTypes setDeviceDisableStatus(SystemTypes t)
	{
		returned = false;
		boolean flag = false;
		flag = SendToServer(t);
		while(!returned){}
		return this.sysType;
	}
	
	/**
	 * this method will be used to enter car to the lot
	 * @param t the order or the subscription based on that the car can get into the lot.
	 * @return the proper message for the result of the operation.
	 */
	
	public SystemTypes enterCar(SystemTypes t)
	{
		returned = false;
		boolean flag = false;
		t.setSysMode(SystemMode.ENTER_CAR);
		flag = SendToServer(t);
		while(!returned){}
		return this.sysType;
	}
	
	/**
	 * this method will be used to remove car to the lot
	 * @param t the order or the subscription based on that the car is in the lot.
	 * @return the proper message for the result of the operation.
	 */
	
	public SystemTypes removeCar(SystemTypes t)
	{
		returned = false;
		boolean flag = false;
		t.setSysMode(SystemMode.REMOVE_CAR);
		flag = SendToServer(t);
		while(!returned){}
		return this.sysType;
	}
	
		
	/**
	 * this method will send the received lot to DB for initialization
	 * @param sysType - the lot to be initialized
	 * @return - the string representing the result of the process
	 */
		
	public SystemTypes ExecuteLotInitialization(SystemTypes sysType)
	{
		returned = false;
		sysType.setSysMode(SystemMode.LOT_INIT);
		boolean flag = SendToServer(sysType);
		while (!returned){}
		if (!flag)
		{
			switch (this.sysType.getSysMode())
			{
				case SYS_ERR:
				{
					this.sysType.setObj("Client - Server Connection Failed!");
					break;
				}
				case FAIL:
				{
					this.sysType.setObj("Lot were already initialized - process FAIL!");
					break;
				}
				case DB_CON_ERR:
				{
					this.sysType.setObj("DB connection Failed!");
					break;
				}
			default:
				this.sysType.setObj("Unknown failure in process!");
				break;
			}
		}
		else
			this.sysType.setObj("The initializition ended succesfully!!");
		return this.sysType;
	} //ExecuteLotInitialization
	
	/**
	 * this method will send to the server the time, date and lot to save space at.
	 * @param sysType - the details needed to save a parking space
	 * @return - the string representing the result of the process
	 */
	
	public SystemTypes SendSavingDetails(SystemTypes sysType)
	{
		returned = false;
		sysType.setSysMode(SystemMode.SET_SAVED);
		boolean flag = SendToServer(sysType);
		while(!returned){}
		if (!flag)
		{
			switch (this.sysType.getSysMode())
			{
				case SYS_ERR:
				{
					this.sysType.setObj("Client - Server Connection Failed!");
					break;
				}
				case FAIL:
				{
					this.sysType.setObj("Can't save the parking space!!");
					break;
				}
				case DB_CON_ERR:
				{
					this.sysType.setObj("DB connection Failed!");
					break;
				}
				case EMPTY_RES:
				{
					this.sysType.setObj("No praking Spaces available!");
					break;
				}
				
			default:
				this.sysType.setObj("Unknown failure in process!");
				break;
			}
		}
		else
			this.sysType.setObj("parking space saving ended succesfully!!");
		
		return this.sysType;
	}
	
	/**
	 * This method will ask to find available parking lot.
	 * @param sysType - will receive the request for new parking lot 
	 * @return - the number of free parking lot or the proper error message
	 */
	
	public SystemTypes FullParkingLot(SystemTypes sysType,String s)
	{
		VCP.currentLot.setLotStatus(s);
		returned = false;
		Serializable obj[] = new Serializable[2];
		obj[0] = s;
		obj[1] = sysType.getObj();
		sysType.setObj(obj);
		sysType.setSysMode(SystemMode.SET_FULL);
		boolean flag = SendToServer(sysType);
		while(!returned){}
		if (!flag)
		{
			switch (this.sysType.getSysMode())
			{
				case SYS_ERR:
				{
					this.sysType.setObj("Client - Server Connection Failed!");
					break;
				}
				case DB_CON_ERR:
				{
					this.sysType.setObj("DB connection Failed!");
					break;
				}
				case EMPTY_RES:
				{
					this.sysType.setObj("Sorry, But all of our parking lots are full!");
					break;
				}
			}
		}
		return this.sysType;
	} // FullParkingLot
	
	/**
	 * This method will ask for the actual parking time of specific car
	 * @param sysType - will receive the details needed for the query
	 * @return - the actual parking time or the proper error message
	 */
	
	public SystemTypes GetActualParkingTime(SystemTypes sysType)
	{
		returned = false;
		sysType.setSysMode(SystemMode.GET_ACT_TIME);
		boolean flag = SendToServer(sysType);
		if (!flag)
		{
			switch (this.sysType.getSysMode())
			{
				case SYS_ERR:
				{
					this.sysType.setObj("Client - Server Connection Failed!");
					break;
				}
				case FAIL:
				{
					this.sysType.setObj("Order isn't closed yet!!");
					break;
				}
				case DB_CON_ERR:
				{
					this.sysType.setObj("DB connection Failed!");
					break;
				}
				case EMPTY_RES:
				{
					this.sysType.setObj("Incorrect order number!");
					break;
				}
				default:
				{
					Date date[] = new Date[2];
					date = (Date[]) sysType.getObj();
					long diff = getDateDiff(date[0],date[1],TimeUnit.MINUTES);
					double hours = diff / 60.0;
					double minutes = diff % 60.0;
					Serializable ans[] = new Serializable[2];
					ans[0] = hours;
					ans[1] = minutes;
					this.sysType.setObj(ans);
				break;
				}
			}
		}
		return this.sysType;
	} //GetActualParkingTime
	
	/**
	 * Get a difference between two dates
	 * @param date1 the old date
	 * @param date2 the new date
	 * @param timeUnit the unit in which you want the difference
	 * @return the difference value, in the provided unit
	 */
	
	public static long getDateDiff(Date date1, Date date2, TimeUnit timeUnit) {
	    long diffInMillies = date2.getTime() - date1.getTime();
	    return timeUnit.convert(diffInMillies,TimeUnit.MILLISECONDS);
	}
		
	
	
	// Interface override method *************************************

	@Override
	public boolean SendToServer(Serializable obj) {
		VCP.client.send(obj);
		sysType = (SystemTypes) VCP.client.getResult();
		if (sysType.getSysMode() != SystemMode.OK)
		{
			returned = true;
			return false;
		}
		returned = true;
		return true;
	}
	
	// Getters and Setters ***************************************************

	/**
	 * @return the sysType
	 */
	public SystemTypes getSysType() {
		return sysType;
	}

	/**
	 * @param sysType the sysType to set
	 */
	public void setSysType(SystemTypes sysType) {
		this.sysType = sysType;
	}

	/**
	 * @return the returned
	 */
	public boolean isReturned() {
		return returned;
	}

	/**
	 * @param returned the returned to set
	 */
	public void setReturned(boolean returned) {
		this.returned = returned;
	}

}
